# !/usr/bin/python2.7
# -*- coding: UTF-8 -*-

###/usr/lib/python2.7/curses

import os
import re
import sys
import shutil
import time
import datetime
import binascii
import struct
import mblue
import curses
import thread
import locale
import mcurses
import mt_ota



exitflag = False

def printusage():
    print "Usage:"
    print "     sudo python bleconn.py mac [xx:xx:xx:xx:xx:xx]"
    print '     io      just input or output'
    print '     sdfl    [filepath] send file to dev'
    print '     supp    [begin time,length] Supplements data'
    print '     ota     [filepath] upgrade sub dev'
    print "     -h      [help]"
    return

def requestParameter(par):
    tar = [0xBE,0xBE,0x21,0x01,0x07,0x07,0x44,0x55,0x56,0x1D,0x09,0x8E,0xED,0xED] #len=14
    pa = par.split()
    if pa[0][0:2].lower()=='0x':
        pa[0]=pa[0][2:]
        tm=map(lambda x:int(x,16),[pa[0][i:i+2] for i in xrange(0,len(pa[0]),2)])
    elif re.search(r'\A[a-fA-F]+\Z',pa[0]) is None:
        t=map(int,[pa[0][i:i+2] for i in xrange(0, len(pa[0]), 2)])
        tm=((t[0] - 10) << 26) + ((t[1] - 1) << 22) + (t[2] << 17) + ((t[3] - 1) << 12) + ((t[4] - 1) << 6) + (t[5])
        tm=hex(tm).zfill(8).upper()[2:]
        tm=map(lambda x:int(x,16),[tm[i:i+2] for i in xrange(0,len(tm),2)])

    tar[-5],tar[-6],tar[-7],tar[-8]=tm[0],tm[1],tm[2],tm[3] 
    length = int(pa[1])
    tar[-3] = length >> 8
    tar[-4] = length & 0xff
    return tar 

def displayMenu(win,x,y,wformat):
    win.display_info('%-s' % (win.getdisplaysize()[1] * ">"),x,y,3)
    win.display_info('%-100s' % '',x,y+1)
    win.display_info(' You can choose the following: (format %s)'%(wformat),x,y+2,1)
    win.display_info(' (1) Press \'Esc\' to return or input \'quit\' to exit',x,y+3,1)
    win.display_info(' (2) Input \'upgrade + filepath\' to upgrade the select dev',x,y+4,1)
    win.display_info(' (3) Press anything to send and \'ctrl+x\' turn \'txt\' or \'16\' format',x,y+5,1)
    win.display_info(' Input:   ',x,y+6,1)
    return x+10,y+6

def sendfile(win,dev,chand,filepath):
    fs=open(filepath,'r')
    filesize=os.path.getsize(filepath)
    bgtime=datetime.datetime.now()
    read=fs.read(128)
    while (read != ''):
        #win.mprint(read)
        sendsize=fs.tell()
        t=(datetime.datetime.now()-bgtime).seconds
        win.getscr().clear()
        win.display_info('filesize: %d Byte ,sendsize: %d Byte ,sendspeed: %d Bps'%(filesize,sendsize,(t>0) and (sendsize/float(t)) or (sendsize)),0,0)
        win.progressbar(float(sendsize)*100/filesize,0,1,50)
        win.display_info('usetime: %d s'%(t),0,2)

        dev.write_char(chand,read,True)
        read=fs.read(128)

    fs.close()
    return True

def upgrade(win,dev,chand,filepath):
    mt_ota.main_loop(dev,chand,filepath,win)
    return

threadlock=thread.allocate_lock()
def keyboard_thread(win,subwin,dev,chand,cnotify,x,y,menuh,writedataformat):
    global exitflag
    revlen=None
    while exitflag == False:
        read=dev.read_char(chand,0.1)
        if read is not None:
            read=read['d'][0]
            if revlen is not None:
                revlen=revlen+len(read)
            try:
                read.decode('utf-8')
            except UnicodeDecodeError as e:
                read=binascii.b2a_hex(read).upper()+'\n'
            subwin.mprint(read)
            if read=='BEBE11001600000000000000000000000000000000000000000000EDED\n':
                win.display_info('supp end:%s supplen:%d'%(datetime.datetime.now(),revlen),40,4)
                revlen=None
                win.display_info('Press any key to quit   ',0,5)
                win.get_ch_and_continue()
                break

        instr=win.get_str_keyboard(x,y)
        if instr is False:
            continue
        if instr=='Esc' or instr=='quit' or instr=='Ctrl+e':
            exitflag=True
            #threadlock.acquire()
            #threadlock.release()
        elif instr=='Ctrl+x':
            writedataformat = ((writedataformat == 'hex') and 'txt' or 'hex')
            displayMenu(win,0,win.getdisplaysize()[0]-menuh,writedataformat)
        elif 'upgrade' in instr and (len(instr.split()) == 2):
            filepath=instr.split()[1]
            if os.path.isfile(filepath):
                #threadlock.acquire()
                upgrade(subwin,dev,chand,filepath)
                #threadlock.release()
            else:
                win.display_info('path error              ',0,4)
        elif 'sendfile' in instr and (len(instr.split()) == 2):
            filepath=instr.split()[1]
            if os.path.isfile(filepath):
                #threadlock.acquire()
                sendfile(subwin,dev,chand,filepath)
                #threadlock.release()
            else:
                win.display_info('path error              ',0,4)
        elif 'supp' in instr and (len(instr.split()) == 3):
            #threadlock.acquire()
            win.display_info('supp start:%s'%datetime.datetime.now(),0,4)
            revlen=0
            rqst=requestParameter(' '.join(instr.split()[1:]))
            dev.write_char(chand,"".join(map(chr,rqst)),True)
            #threadlock.release()
        elif instr.split()[0] == 'savewin':
            if len(instr.split()) > 1:
                res = subwin.savewin(instr.split()[1])
            else:
                res = subwin.savewin(r'./winlog.log')
            if res:
                win.display_info('save success',0,4)
        else:
            if instr == 'Enter':
                instr = '\r\n'
            if chand is not None and cnotify:
                #threadlock.acquire()
                if writedataformat == 'txt':
                    dev.write_char(chand,instr,True)
                elif writedataformat == 'hex':
                    instr = instr.replace(' ','')
                    if re.search(r'\A[0-9a-fA-F]+\Z',instr):
                        dev.write_char(chand,''.join(map(chr,[int(instr[i:i+2],16) for i in xrange(0, len(instr), 2)])),True)
                    else:
                        win.display_info('Contains error data',0,4)
                #threadlock.release()
    return

def read_char_thread(win,dev,chand):
    global exitflag
    while exitflag == False:
        threadlock.acquire()
        read=dev.read_char(chand,0.1)
        threadlock.release()
        read=read['d'][0]
        try:
            read.decode('ascii')
        except UnicodeDecodeError as e:
            read=binascii.b2a_hex(read).upper()+'\n'
        win.mprint(read)
    return

def main():
    global exitflag
    if '-h' in sys.argv:
        printusage()
        exit()
    if 'mac' in sys.argv:
        mac = sys.argv[(sys.argv.index("mac") + 1)]
    else:
        printusage()
        exit()

    writedataformat = 'txt'
    menuh = 12
    titleh = 6 
    dev = mblue.bluedev()
    (screen_rows, screen_columns)=mcurses.displaysize()
    win = mcurses.mcurwin(hight=screen_rows,width=screen_columns)
    #try:
    (ph,pw,py,px)=win.getdisplaysize()
    subwin=win.newsubwin(ph-menuh-titleh-1,pw,py+titleh,px)
    win.display_info('Connecting to %s ...' % (mac),0,0)
    (inputx,inputy)=displayMenu(win,0,win.getdisplaysize()[0]-menuh,writedataformat)
    #try:
    conhandle=dev.connect(mac)
    if not conhandle is None:
        win.display_info('Connected',0,1)
        chand = dev.getcharhandleByUUID('1101','8888')
        if chand is not None:
            win.display_info('discovery 1101 8888 char',0,2)
            if dev.char_notify(chand) is True:
                cnotify = True
                win.display_info('turn on notify success',0,3)
                #thread.start_new_thread(read_char_thread,(subwin,dev,chand))
            else:
                cnotify = False 
                win.display_info('turn on notify fail',0,3)
        else:
            cnotify = False 
            win.display_info('no discovery 1101 8888 char',0,2)

        keyboard_thread(win,subwin,dev,chand,cnotify,inputx,inputy,menuh,writedataformat)
    else:
        win.display_info('Connect fail',0,1)
        win.display_info('Press any key to continue...',0,win.getdisplaysize()[0]-menuh-1)
        win.get_ch_and_continue()

    #except:
    #    win.display_info('Connect fail',0,1)
    #    win.display_info('Press any key to continue...',0,win.getdisplaysize()[0]-11)
    #    win.get_ch_and_continue()
    #except Exception,e:
    #    raise e
    #finally:

    dev.disconnect()
    win.unset_win()  
    return

 
if __name__ == '__main__':
    #try:
    main()
    #except:
    #    pass
    exit()
    
    





